<?php

declare(strict_types=1);

namespace App\Service;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use App\Library\Common;
use App\Model\FlyGourmetMealConf;
use App\Model\FlyOrder;
use App\Model\FlyOrderProduct;
use App\Model\FlyShop;
use App\Model\FlyShopOpenTime;
use App\Model\ReservedSeatsSet;
use App\Model\ShopOrderReview;
use Hyperf\Database\Model\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Hyperf\Validation\Rule;
use Hyperf\Di\Annotation\Inject;

/**
 * 订座服务
 * Class SeatsOrderService
 * @package App\Service
 */
class SeatsOrderService extends BaseService
{
    const FOOD_TYPE_SEAT = 2; // 订座
    const FOOD_TYPE_ORDER = 3; // 点餐

    /**
     * @Inject
     * @var FileinfoService
     */
    private $file;

    /**
     * @Inject
     * @var FlyPayOrderService
     */
    private $payOrder;

    /**
     * @Inject
     * @var SkuService
     */
    private $sku;

    /**
     * @Inject
     * @var FlyCartService
     */
    private $cart;

    /**
     * @Inject
     * @var RequestInterface
     */
    private $request;

    /**
     * @Inject
     * @var ValidatorFactoryInterface
     */
    private $validate;

    /**
     * 订座参数验证
     * @param int $user_id
     * @param bool $commit
     * @return array
     */
    public function seatVerify(int $user_id, $commit = false): array
    {
        $params = $this->request->inputs(['seat_params', 'shop_id']);
        if (empty($params['shop_id'])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '缺少参数');
        }
        if ($commit && (empty($params['seat_params']) || !is_array($params['seat_params']))) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '缺少参数2');
        }

        $shop = make(FlyShopService::class)->getShopInfo((int)$params['shop_id']);
        if (empty($shop) || $shop['food_state'] != FlyShopService::STATUS_UP) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '店铺已下架');
        }

        // 订座验证
        $shop_sets = make(ReservedSeatsSet::class)
            ->with(['with_shop_info'])
            ->where('shop_id', '=', $params['shop_id'])
            ->first();
        if (empty($shop_sets) || empty($shop_sets->with_shop_info) || $shop_sets->status == 0) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '店铺未开启订座功能');
        }
        $shop_set = $shop_sets->toArray();
        if ($commit) {
            // Seat: take_room
            $res = $this->validate->make($params['seat_params'], [
                'people_num' => ['required', 'min:1', 'max:15'],
                'date_time' => ['required', 'int'], // 在店铺营业时间内
                'is_vip' => ['required', Rule::in([0, 1])],// 是否包间
                'link_name' => ['required', 'max:32'],
                'phone' => ['required', 'max:20'],
                'remark' => ['nullable', 'max:150']
            ]);
            if ($params['seat_params']['is_vip'] == 1 && $params['seat_params']['people_num'] < $shop_set['min_person']) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '包间' . $shop_set['min_person'] . '人起订');
            }
            if ($res->fails()) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, $res->errors()->first());
            }
            if ($params['seat_params']['is_vip'] == 1 && $shop_set['is_unshared'] == 0) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '不支持包间');
            }
            $date_time = date('Hi', $params['seat_params']['date_time']);
            if (!make(FlyShopOpenTime::class)
                ->where('shop_id', '=', $params['shop_id'])
                ->where('start_time', '<=', $date_time)
                ->where('end_time', '>=', $date_time)
                ->exists()) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '非商家营业时间');
            }
            if ($params['seat_params']['date_time'] < time()) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '预约时间错误');
            }

            if (($params['seat_params']['date_time'] - time()) > 86400 * ($shop_sets->advance_days)) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '最晚可预定' . $shop_sets->advance_days . "天后的座位");
            }

        }
        if (empty($params['seat_params']['people_num'])) {
            $order_price = 0.00;
        } else {
            $order_price = ($shop_set['deposit_type'] == 3) ? $shop_set['single_deposit'] : ($shop_set['deposit_type'] == 1 ? 0 : (Common::fen2yuan(Common::yuan2fen(floatval($shop_set['single_deposit']) * $params['seat_params']['people_num']))));
        }


        $params['seat_params'] = [
            'people_num' => $params['seat_params']['people_num'] ?? "",
            'date_time' => $params['seat_params']['date_time'] ?? "",
            'is_vip' => $params['seat_params']['is_vip'] ?? "",
            'link_name' => $params['seat_params']['link_name'] ?? "",
            'phone' => $params['seat_params']['phone'] ?? "",
            'remark' => $params['seat_params']['remark'] ?? "",
            'logo' => $shop['certificate_att'][0]['file_info']['url'] ?? ""
        ];

        $order_data = [
            'shop_id' => $params['shop_id'],
            'order_style' => 2,
            'order_sn' => make(FlyOrderService::class)->generateOrderSn(),
            'order_status' => $shop_set['deposit_type'] == 1 ? FlyOrderService::STATUS_WAIT_RECEIVE : FlyOrderService::STATUS_WAIT_PAY,
            'order_price' => $order_price,
            'pay_price' => $order_price,
            'product_price' => $order_price,
            'user_id' => $user_id,
            'link_name' => $params['seat_params']['link_name'] ?? "",
            'phone' => $params['seat_params']['phone'] ?? "",
            'shop_name' => $shop_set['with_shop_info']['shop_name'] ? $shop_set['with_shop_info']['shop_name'] : "",
            'create_time' => time(),
            'remark' => $params['seat_params']['remark'] ?? "",
            'paid_time' => $shop_set['deposit_type'] == 1 ? time() : 0,
            'is_pay' => $shop_set['deposit_type'] == 1 ? 1 : 0,
            'product_num' => 1,
            'charge_off_code' => rand(100000, 999999),
            'virtual_form_info' => json_encode($params['seat_params'], JSON_PARTIAL_OUTPUT_ON_ERROR), // 已选参数
            'virtual_form_arr' => $params['seat_params'], // 已选参数数组
            'seat_can_af_end_time' => (!$commit) ? 0 : ($shop_set['cancel_type'] == 1 ? $params['seat_params']['date_time'] - 60 * $shop_set['before_minute'] : -1),// 未消费随时退不需审核，
        ];

        $pay_order_data = [
            'pay_order_sn' => make(FlyOrderService::class)->generateOrderSn('P'),
            'user_id' => $user_id,
            'is_pay' => $shop_set['deposit_type'] == 1 ? 1 : 0,
            'order_price' => $order_data['order_price'],
            'create_time' => time(),
            'pay_time' => $shop_set['deposit_type'] == 1 ? time() : 0,
            'pay_price' => $order_data['order_price'],
            'product_price' => $order_data['order_price'],
            'order_style' => FlyOrderService::STYLE_SEAT // 订座订单
        ];
        $order_data['pay_order_sn'] = $pay_order_data['pay_order_sn'];

        return [
            'order_data' => $order_data,
            'pay_order_data' => $pay_order_data
        ];
    }

    /**
     * 点餐确认
     * @param int $user_id 下单用户
     * @param int $shop_id 需要结算的店铺ID
     * @param bool $commit 是否结算
     * @return array
     */
    public function orderVerify(int $user_id, int $shop_id, bool $commit = false): array
    {
        $shop = make(FlyShopService::class)->getShopInfo($shop_id);
        if (empty($shop) || $shop['food_state'] != FlyShopService::STATUS_UP) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '店铺已下架');
        }

        $params = $this->request->all();
        if ($commit && (empty($params['link_name']) || empty($params['phone']) || empty($params['take_way']))) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '缺少参数');
        }
        if ($commit && !preg_match("/^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$/", strval($params['phone']))) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '手机号格式错误');
        }
        $meal_conf = make(FlyGourmetMealConf::class)->where(['shop_id' => $shop_id, 'is_reservation' => 1])->whereNull('deleted_at')->value('consume_type');
        $conf = empty($meal_conf) ? false : (is_array($meal_conf) ? $meal_conf : json_decode($meal_conf, true));
        if ($commit && (!$conf || !in_array($params['take_way'], $conf))) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '不支持' . ($params['take_way'] == 1 ? "堂食" : "打包带走"));
        }
        if (!empty($params['take_way'])) {
            // 1到店 2打包
            $params['take_way'] = $params['take_way'] == 1 ? 1 : 2;
        }
        // 获取店铺点餐信息进行结算
        $carts = $this->cart->getCartSku($user_id, FlyCartService::CART_STYLE_ORDER, $shop_id);
        if (empty($carts)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '没有可结算的餐品!');
        }
        if ($commit && !empty($params['date_time']) && $params['date_time'] < time()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '预约时间错误0');
        }
        if ($commit && !empty($params['date_time'])) {
            $date_time = date("Hi", $params['date_time']);
            if (empty($date_time)) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '预约时间错误');
            } elseif (!make(FlyShopOpenTime::class)
                ->where('shop_id', '=', $shop_id)
                ->where('start_time', '<=', $date_time)
                ->where('end_time', '>=', $date_time)
                ->exists()) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '预约时间错误，不在营业时间内' . date('Y-m-d H:i', $date_time));
            }
        }

        $form_info = [
            'link_name' => $params['link_name'] ?? "",
            'phone' => strval($params['phone'] ?? ""),
            'take_way' => $params['take_way'] ?? 1,
            'date_time' => $params['date_time'] ?? 0,
            'logo' => $params['virtual_form_arr']['logo'] ?? ""
        ];

        // 订单信息
        $order_data = [
            'shop_id' => $shop_id,
            'order_status' => FlyOrderService::STATUS_WAIT_PAY,
            'order_style' => FlyOrderService::STYLE_ORDER,
            'order_sn' => make(FlyOrderService::class)->generateOrderSn(),
            'order_price' => 0,
            'user_id' => $user_id,
            'link_name' => $params['link_name'] ?? "",
            'pay_price' => 0,
            'phone' => strval($params['phone'] ?? ""),
            'shop_name' => $shop['shop_name'],
            'create_time' => time(),
            'remark' => $params['remark'] ?? "",
            'product_num' => 0,
            'product_price' => 0,
            'charge_off_code' => rand(100000, 999999),
            'virtual_form_info' => json_encode($form_info, JSON_PARTIAL_OUTPUT_ON_ERROR),
            'virtual_form_arr' => $form_info,
            'products' => []
        ];

        $products = $this->cart->getCartSku($user_id, FlyCartService::CART_STYLE_ORDER, $shop_id);
        if (empty($products['data']) || empty($products['data']['carts'])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '没有可以结算的商品，快去加入购物车吧!');
        }

        foreach ($products['data']['carts'] as &$product) {
            // 商品单价
            $single_price = Common::yuan2fen(floatval($product['sku_info']['step_price']));
            $subtotal = $single_price * $product['quantity'];
            $tmp_product = [
                'order_id' => 0,
                'pay_order_id' => 0,
                'sku_id' => $product['sku_id'],
                'shop_id' => $product['shop_id'],
                'product_id' => $product['product_id'],
                'sku_name' => $product['sku_info']['sku_name'],
                'product_name' => $product['sku_info']['with_product']['product_name'],
                'single_price' => $product['sku_info']['step_price'],
                'quantity' => $product['quantity'],
                'subtotal' => Common::fen2yuan($subtotal),
                'sku_img' => $product['sku_info']['with_product']['main_pic'][0]['file_info']['url'] ?? "",
            ];
            $tmp_product['product_info'] = $product;
            $order_data['product_num'] += $product['quantity'];// 商品总数
            $order_data['product_price'] += $subtotal;// 商品总金额
            $order_data['order_price'] += $subtotal;// 订单金额
            $order_data['pay_price'] += $subtotal;
            $order_data['products'][] = $tmp_product;
        }

        $pay_order_data = [
            'pay_order_sn' => make(FlyOrderService::class)->generateOrderSn('P'),
            'user_id' => $user_id,
            'order_price' => $order_data['order_price'],
            'create_time' => time(),
            'product_price' => $order_data['order_price'],
            'pay_price' => $order_data['pay_price'],
            'order_style' => FlyOrderService::STYLE_ORDER // 点餐订单：无需售后配置，支持仅退款。核销成功后退款需审核
        ];
        // 点餐
//        if (!$commit) {
        $order_data['pay_price'] = Common::fen2yuan($order_data['pay_price']);
        $order_data['order_price'] = Common::fen2yuan($order_data['order_price']);
        $order_data['product_price'] = Common::fen2yuan($order_data['product_price']);
        $pay_order_data['pay_price'] = $order_data['pay_price'];
        $pay_order_data['order_price'] = $order_data['order_price'];
        $pay_order_data['product_price'] = $order_data['product_price'];
//        }

        $order_data['pay_order_sn'] = $pay_order_data['pay_order_sn'];
        return [
            'pay_order_data' => $pay_order_data,
            'order_data' => $order_data,
        ];
    }

    /**
     * 服务订单创建：订座服务，点餐服务
     * @param int $user_id
     * @param array $params
     * @param int $food_style 美食订单类型
     * @return string pay_order_sn 支付单号
     */
    public function serverCreate(int $user_id, array $params, $food_style = self::FOOD_TYPE_SEAT): string
    {
        if (empty($user_id) || empty($params) || empty($food_style)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '缺少参数');
        }
        Db::beginTransaction();
        try {
            $pay_order_id = $this->payOrder->createOrder($params['pay_order_data'], FlyOrderService::STYLE_SEAT);
            if (!$pay_order_id) {
                Db::rollBack();
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '支付单生成失败');
            }
            $params['order_data']['pay_order_id'] = $pay_order_id;
            // 生成订单
            $order_instance = make(FlyOrderService::class)->getInstance();
            unset($params['order_data']['virtual_form_arr']);
            $products = $params['order_data']['products'] ?? [];
            if (isset($params['order_data']['produces'])) unset($params['order_data']['products']);
            foreach ($params['order_data'] as $fields => $val) {
                if (!is_array($val)) {
                    $order_instance->$fields = $val;
                }
            }
            if (!$order_instance->save()) {
                Db::rollBack();;
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '订单生成失败');
            }

            // 点餐订单需要记录餐品
            if ($food_style == self::FOOD_TYPE_ORDER) {
                foreach ($products as $product) {
                    $data = array_filter($product, function ($p) {
                        if (!in_array($p, ['sku_id', 'product_id', 'sku_name', 'product_name', 'single_price', 'quantity', 'subtotal', 'sku_img', 'free_num', 'support_af_types', 'can_af_apply_duration'])) {
                            return false;
                        } else {
                            return true;
                        }
                    }, ARRAY_FILTER_USE_KEY);
                    $p_instance = make(FlyOrderProduct::class);
                    foreach ($data as $f => $v) {
                        $p_instance->$f = $v;
                    }
                    $p_instance->order_id = $order_instance->order_id;
                    $p_instance->pay_order_id = $pay_order_id;
                    if (!$p_instance->save()) {
                        Db::rollBack();
                        throw new BusinessException(ErrorCode::NORMAL_ERROR, '商品保存失败');
                    }
                }
            }

        } catch (\Throwable $exception) {
            Db::rollBack();
            throw new BusinessException(ErrorCode::NORMAL_ERROR, "下单失败:" . $exception->getMessage());
        }
        Db::commit();
        return $params['order_data']['pay_order_sn'];
    }

    /**
     * 商品评价
     * @param int $user_id
     * @return bool
     */
    public function review(int $user_id): bool
    {
        $params = $this->request->inputs(['order_id', 'sku_id', 'score', 'reviews', 'reviews_show']);
        $re = $this->validate->make($params, [
            'order_id' => ['required', 'integer'],
            'sku_id' => ['nullable', 'integer',
                Rule::unique('fly_shop_order_reviews', 'sku_id')
                    ->where('order_id', $params['order_id'])
                    ->where('reviewer', $user_id)
            ], // 对商品评价
            'score' => ['required', Rule::in([1, 2, 3, 4, 5])],
            'reviews' => ['required', 'max:150'],
            'reviews_show' => ['nullable', 'array']
        ],
            [
                'sku_id.unique' => '已评论，不可重复评论'
            ]
        );
        if ($re->fails()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, $re->errors()->first());
        }
        $params['user_id'] = $user_id;
        if (!empty($params['sku_id'])) {
            $order_info = make(FlyOrder::class)
                ->with(['with_products'])
                ->whereHas('with_products', function ($where) use ($params) {
                    // 商品评论
                    $where->where('sku_id', '=', $params['sku_id']);
                })
                ->where('is_pay', '=', 1)
                ->where('order_status', '=', FlyOrderService::STATUS_FINISHED)
                ->where('order_id', '=', $params['order_id'])
                ->where('user_id', '=', $user_id)
                ->first();
        } else {
            $order_info = make(FlyOrder::class)
                ->with(['with_products'])
                ->where('is_pay', '=', 1)
                ->where('order_status', '=', FlyOrderService::STATUS_FINISHED)
                ->where('order_id', '=', $params['order_id'])
                ->where('user_id', '=', $user_id)
                ->first();
        }

        if (empty($order_info)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '无法评论');
        }
        // 有商品订单需要选择商品id
        if (!empty($order_info->with_products->toArray()) && empty($params['sku_id'])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '未选择要评价的商品');
        }

        $instance = make(ShopOrderReview::class);
        $instance->shop_id = $order_info->shop_id;
        $instance->sku_id = empty($params['sku_id']) ? 0 : intval($params['sku_id']);
        $instance->product_id = !empty($order_info->with_products->toArray()) ? $order_info->with_products->first()->product_id : 0;
        $instance->order_style = $order_info->order_style;
        $instance->order_id = $order_info->order_id;
        $instance->reviews = $params['reviews'];
        $instance->score = $params['score'];
        $instance->reviewer = $params['user_id'];
        $instance->create_time = time();
        if (!empty($params['reviews_show'])) {
            $files = $this->file->getFileinfo($params['reviews_show']);
            $att = [];
            foreach ($files as $f) {
                if ($f['user_id'] != $user_id) {
                    throw new BusinessException(ErrorCode::NORMAL_ERROR, '违规图片');
                }
                $att[] = [
                    'fileinfo_id' => $f['fileinfo_id'],
                    'url' => $f['url']
                ];
            }
            $instance->reviews_show = $att;
        }
        if (!$instance->save()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '评论失败');
        }
        $shop_instance = make(FlyShop::class)->find($order_info['shop_id']);
        $shop_instance->food_avg_score = (float)sprintf('%.2f', ($shop_instance->food_avg_score + $params['score']) / 2);
        if (!$shop_instance->save()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '评论失败2');
        }
        return true;
    }

    /**
     * 评价列表
     * @param int $user_id
     * @param int $id 1店铺
     * @param int $style 1店铺评论 2商品评论
     * @return Builder
     */
    public function reviewList(int $user_id, int $id, $style = 0): Builder
    {
        return make(ShopOrderReview::class)
            ->with(['with_order'])
            ->leftJoin('app_user', 'fly_shop_order_reviews.reviewer', '=', 'app_user.id')
            ->select(['fly_shop_order_reviews.*', 'app_user.nickname', 'app_user.avatar'])
            ->where(function ($where) use ($id, $style) {
                if ($style == 1) {
                    $where->where('order_style', '=', 2)
                        ->where('shop_id', '=', $id);
                } else {
                    $where->whereIn('order_style', [1, 3])
                        ->where('product_id', '=', $id);
                }
            })->orderBy('create_time');
    }

    /**
     * 美食店铺订单核销
     * @param int $user_id
     * @return bool
     */
    public function serviceUse(int $user_id): bool
    {
        $order_id = $this->request->input('order_id', 0);
        $charge_type = $this->request->input('charge_type', 0);
        $charge_off_code = $this->request->input('charge_off_code', '');
        if (empty($order_id) || empty($charge_type) || !in_array($charge_type, [1, 2])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '核销方式错误');
        }

        if ($charge_type == 2 && empty($charge_off_code)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '未填写核销码');
        }
        $order = make(FlyOrder::class)->find($order_id);
        if (empty($order) || !in_array($order->order_style, [2, 3]) || $order->is_pay != 1 || $order->order_status != FlyOrderService::STATUS_WAIT_RECEIVE) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '订单不存在');
        }
        if ($charge_type == 2 && $order->charge_off_code != $charge_off_code) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '核销码错误');
        }
        $order->charge_type = $charge_type;
        $order->order_status = FlyOrderService::STATUS_FINISHED;
        $order->is_received = 1;
        $order->received_time = time();
        if (!$order->save()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '订单状态更新错误');
        }
        return true;
    }
}